package com.yonyou.crm.sys.modules.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.yonyou.crm.sys.modules.service.CurrencyBizServiceImpl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.yonyou.crm.base.doc.entity.BaseDocDetailVO;
import com.yonyou.crm.base.doc.entity.BaseDocVO;
import com.yonyou.crm.base.doc.service.BaseDocBizServiceImpl;
import com.yonyou.crm.common.biz.service.BaseBizServiceImpl;
import com.yonyou.crm.common.enumeration.service.EnumBizServiceImpl;
import com.yonyou.crm.common.exception.CrmBusinessException;
import com.yonyou.crm.sys.modules.constants.EnumSource;
import com.yonyou.crm.sys.modules.constants.FieldType;
import com.yonyou.crm.sys.modules.entity.ApiVO;
import com.yonyou.crm.sys.modules.entity.FieldTypeVO;
import com.yonyou.crm.sys.modules.entity.FieldVO;
import com.yonyou.crm.sys.modules.entity.CurrencyVO;
import com.yonyou.crm.sys.modules.entity.ModuleVO;
import com.yonyou.crm.sys.modules.events.FieldDeleteEvent;
import com.yonyou.iuap.context.InvocationInfoProxy;

@Service
public class FieldBizServiceImpl extends BaseBizServiceImpl<FieldVO>{
	@Autowired
	private  ApplicationEventPublisher publisher;
	@Autowired
	private ModuleBizServiceImpl moduleServiceImpl;
	@Autowired 
	private FieldHandler fieldHandler;
	@Autowired 
	AdministratorManage administratorManage;
	@Autowired
	private CurrencyBizServiceImpl currencyBizServiceImpl;	
	@Autowired
	private EnumBizServiceImpl enumBizServiceImpl;
	@Autowired
	private BaseDocBizServiceImpl baseDocBizServiceImpl;
	@Autowired
	private ApiBizServiceImpl apiBizServiceImpl;
	
	// 最多支持几级级联
	private final Integer MAX_LEVEL = 3;
	
	/**
	 * 获取属性列表,只支持一级属性,因为只有自定义字段才能删除，所以不需处理预置字段被删除的情况
	 * 
	 * @return
	 */
	public List<FieldVO> getFieldList(Long objId){
		Map<String, Object> paramMap = new HashMap<String, Object>();
		String tenantIdStr = (String) InvocationInfoProxy.getTenantid();
		Long tenantId = Long.parseLong(tenantIdStr);
		paramMap.put("tenantId", tenantId);
		paramMap.put("objId", objId);

		List<FieldVO> fieldList = new ArrayList<FieldVO>();
		fieldList = dao.selectVoList(FieldVO.class, "ListField", paramMap);
		List<String> customFields = new ArrayList<String>();
		for (FieldVO fieldVO : fieldList) {
			if (fieldVO.getTenantId() != 0) {
				customFields.add(fieldVO.getApiName());
			}
		}
		Iterator<FieldVO> it = fieldList.iterator();
		while (it.hasNext()) {
			FieldVO field = it.next();
			if (field.getTenantId() == 0	&& customFields.contains(field.getApiName())) {
				    it.remove();
			} else {
				assembleField(field);
			}
		}
		return fieldList;
	}
	
	/**
	 * 获取属性列表,只支持一级属性
	 * 
	 * @return
	 */
	public List<FieldVO> getFieldList(Long objId, List<String> fieldNames){
		List<FieldVO> fieldList = getFieldList(objId);
		
		Iterator<FieldVO> it = fieldList.iterator();
		while (it.hasNext()) {
			FieldVO field = it.next();
			if (! fieldNames.contains(field.getApiName())) {
				    it.remove();
			}
		}
		return fieldList;
	}
	
	public Map<String, FieldVO> getFieldListMap(Long objId){
		List<FieldVO> fieldList = getFieldList(objId);
		Map<String, FieldVO> fieldListMap = new HashMap<String, FieldVO>();
		for (FieldVO fld:fieldList) {
			fieldListMap.put(fld.getApiName(),fld);
		}
		return fieldListMap;
	}
	/**
	 * 获取属性Map，只支持一级属性
	 * @param objId
	 * @param fieldNames
	 * @return
	 */
	public List<FieldVO> getFieldListMap(Long objId, List<String> fieldNames) {
		List<FieldVO> fieldList = getFieldList(objId);
		Map<String, FieldVO> fieldListMap = new HashMap<String, FieldVO>();
		Iterator<FieldVO> it = fieldList.iterator();
		while (it.hasNext()) {
			FieldVO field = it.next();
			if (fieldNames.contains(field.getApiName())) {
				fieldListMap.put(field.getApiName(), field);
			}
		}
		return fieldList;
	}
	
	/**
	 *  获取属性定义，支持多级属性
	 * @param fullname
	 * @return
	 */
	public FieldVO getField(String fullname ) {
		Integer level = getHierarchyLevel(fullname);
		if (level > MAX_LEVEL +1) {
			throw new CrmBusinessException("字段级联数超过了限制，最多支持"+MAX_LEVEL+"级级联");
		}
		String firstFullName = fullname;
		FieldVO field = null;
		if (level > 2) {
			firstFullName = fullname.split("\\.")[0] + "." + fullname.split("\\.")[1];
		} 
		String tenantIdStr = (String) InvocationInfoProxy.getTenantid();
		Long tenantId = Long.parseLong(tenantIdStr);
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("tenantId", tenantId);
		paramMap.put("fullname", firstFullName);

		List<FieldVO> fields = dao.selectVoList(FieldVO.class, "ListField",
				paramMap);
		for (FieldVO fld : fields) {
			field = fld;
			if (fld.getTenantId() != 0) {
				break;
			}
		}
		if (field == null) {
			throw new CrmBusinessException("属性不存在");
		}
		if (level>2) {
			String fieldName = fullname.substring(firstFullName.length()+1);
			field = getField(field.getRefObjId(),fieldName);
		} else {
			assembleField(field);
		}
		return field;
	}
	
	/**
	 *  获取属性定义，支持多级属性
	 * @param objId
	 * @param name
	 * @return
	 */
	public FieldVO getField(Long objId, String name ) {
		Integer level = getHierarchyLevel(name);
		if (level > MAX_LEVEL) {
			throw new CrmBusinessException("字段级联数超过了限制，最多支持"+MAX_LEVEL+"级级联");
		}
		String apiName = name;
		if (level >1) {
			 apiName = name.split("\\.")[0];
		}
		String tenantIdStr = (String) InvocationInfoProxy.getTenantid();
		Long tenantId = Long.parseLong(tenantIdStr);
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("tenantId", tenantId);
		paramMap.put("objId", objId);
		paramMap.put("apiName", apiName);
		FieldVO field = null;
		// TODO 性能优化，从缓存取
		List<FieldVO> fields = dao.selectVoList(FieldVO.class, "ListField", paramMap);
		for (FieldVO fld: fields)  {
			field = fld;
			if (fld.getTenantId()  != 0) {
				break;
			}
		}
		if (field == null) {
			throw new CrmBusinessException("属性不存在");
		}
		// 递归来取
		if  (level > 1 && (field.getType().equals(FieldType.Lookup)||field.getType().equals(FieldType.MasterDetail))) {
			field = getField(field.getRefObjId(),name.substring(apiName.length()));
		}
		assembleField(field);
		return field;
	}
	
	public FieldVO saveField(FieldVO fieldVO ) {
		String tenantIdStr = (String) InvocationInfoProxy.getTenantid();
		Long tenantId = Long.parseLong(tenantIdStr);
		String userIdStr = (String)InvocationInfoProxy.getParameter("id");//用户id
		Long userId = Long.parseLong(userIdStr);
		if (!administratorManage.isAdmin(userId)) {
			throw new CrmBusinessException("没有该功能的操作权限");
		}
		if(fieldVO.getRefDocId() != null && !fieldVO.getRefDocId().equals(new Long("0"))){
			fieldVO.setEnumSource(EnumSource.RefDoc);
		}
		fieldVO.setTenantId(tenantId);
		fieldVO.setMobileUiType(FieldType.getMobileUiType(fieldVO.getType()));
		fieldVO.setPcUiType(FieldType.getPcUiType(fieldVO.getType()));
		ModuleVO module = moduleServiceImpl.getModule(fieldVO.getObjId());
		String moduleName = module.getApiName();
		fieldHandler.setSlotAndApiName(fieldVO);
		String fullFieldName = moduleName + "." + fieldVO.getApiName();
		fieldVO.setFullname(fullFieldName);
		Date now = new Date();
		fieldVO.setSortOrder(now.getTime());
		fieldVO.setSysCreatedTime(now);
		fieldVO.setSysModifiedTime(now);
		fieldVO.setSysCreatedUserId(userId);
		fieldVO.setSysModifiedUserId(userId);
		super.saveVO(fieldVO);
		
		return fieldVO;
	}
	
	public FieldVO updateField(FieldVO fieldVO) {
		String tenantIdStr = (String) InvocationInfoProxy.getTenantid();
		Long tenantId = Long.parseLong(tenantIdStr);
		String userIdStr = (String)InvocationInfoProxy.getParameter("id");//用户id
		Long userId = Long.parseLong(userIdStr);
		if (!administratorManage.isAdmin(userId)) {
			throw new CrmBusinessException("没有该功能的操作权限");
		}
		fieldVO.setTenantId(tenantId);
		String fullname = fieldVO.getFullname();
		String apiName = StringUtils.delimitedListToStringArray(fullname, ".")[1];
		fieldVO.setApiName(apiName);
		FieldVO originalField = getField(fieldVO.getObjId(),fieldVO.getApiName());
		Date date = new Date();
		fieldVO.setSysModifiedTime(date);
		if (originalField.getTenantId() == 0) {
			fieldVO.setSysCreatedTime(date);
			// 以下参数要从系统预置数据复制
			copyFromOriginal(fieldVO, originalField);
			fieldVO.setSysModifiedUserId(userId);
			fieldVO.setSysModifiedTime(date);
			fieldVO = super.saveVO(fieldVO);
		} else {
			fieldVO.setSysModifiedUserId(userId);
			fieldVO.setSysModifiedTime(date);
			fieldVO = super.updateVO(fieldVO);
			// 为了返给前端使用
			copyFromOriginal(fieldVO, originalField);
		}
		return fieldVO;
	}
	
	public void deleteField(String fullname ) {
		// 自定义字段目前不涉及关联字段和表达式等，暂时不管
		// 过滤条件中目前没有自定义字段，暂时也不管
		String tenantIdStr = (String) InvocationInfoProxy.getTenantid();
		Long tenantId = Long.parseLong(tenantIdStr);
		String userIdStr = (String)InvocationInfoProxy.getParameter("id");//用户id
		Long userId = Long.parseLong(userIdStr);
		if (!administratorManage.isAdmin(userId)) {
			throw new CrmBusinessException("没有该功能的操作权限");
		}
		FieldVO fieldVO = getField(fullname);
		if (fieldVO.getIsCustom() == 0) {
			throw new CrmBusinessException("系统预置字段不可删除");
		}

		Map<String, Object> deleteMap = new HashMap<String, Object>();
		Date now = new Date();
		deleteMap.put("tenantId", tenantId);
		deleteMap.put("deletedUserId", userId);
		deleteMap.put("sysModifiedUserId", userId);
		deleteMap.put("apiName",fieldVO.getApiName()+"_deletedat"+now.toString());
		deleteMap.put("fullname",fieldVO.getFullname()+"_deletedat"+now.toString());	
		// 作为条件
		deleteMap.put("originalFullname",fieldVO.getFullname());
		// 字段表设置为deleted
		dao.updateSql(FieldVO.class, "setDeleteFlag", deleteMap);
		fieldVO.setTenantId(tenantId);
		fieldVO.setDeletedTime(now);
		fieldVO.setDeletedUserId(userId);
		FieldDeleteEvent event = new FieldDeleteEvent(fieldVO);
		publisher.publishEvent(event);
	}
	
	public List<FieldVO> getCustomFieldList(Long objId,String mysqlDatatype){
		List<FieldVO> fieldList = getFieldList(objId);
		List<FieldVO> mainCustomFieldList =new ArrayList<FieldVO>();
		Iterator<FieldVO> it = fieldList.iterator();
		while (it.hasNext()) {
			FieldVO field = it.next();
			if (field.getIsCustom() == 1 && field.getSlot().startsWith(mysqlDatatype) && !isCompositeField(field.getApiName())) {
					mainCustomFieldList.add(field);
			}
		}
		return mainCustomFieldList;
	}
	
	public List<FieldVO> getCustomFieldList(Long objId){
		List<FieldVO> fieldList = getFieldList(objId);
		List<FieldVO> mainCustomFieldList =new ArrayList<FieldVO>();
		Iterator<FieldVO> it = fieldList.iterator();
		while (it.hasNext()) {
			FieldVO field = it.next();
			if (field.getIsCustom() == 1) {
				mainCustomFieldList.add(field);
			}
		}
		return mainCustomFieldList;
	}
	
	private Boolean isCompositeField(String fieldName) {
		return fieldName.indexOf(".") != -1;
	}
	
	private Integer getHierarchyLevel(String fieldName) {
		return fieldName.split("\\.").length;
	}
	
	private void assembleField(FieldVO field) {
		setCurrency(field);
		setEnum(field);
		setRefDoc(field);
		setApi(field);
		setControlledBy(field);
	}
	

	private void setCurrency(FieldVO field) {
		if (field.getType() == FieldType.Currency) {
			CurrencyVO currency = currencyBizServiceImpl.getCurrency(field.getCurrencyId());
			field.setCurrency(currency);
		}	
	}
	
	private void setEnum(FieldVO field) {
		if (field.getEnumSource() == EnumSource.SysEnum ) {
			List<Map<String,Object>> originalEnums =enumBizServiceImpl.getEnumByCode(field.getEnumCode());
			List<Map<String, Object>> enums = new ArrayList<Map<String,Object>>();
			for (Map<String, Object> originalEnum: originalEnums) {
				Map<String, Object> enumMap = new HashMap<String, Object>();
				enumMap.put("key", originalEnum.get("value").toString());
				enumMap.put("title", originalEnum.get("name"));
				enums.add(enumMap);
			}
			field.setEnums(enums);
		}	
	}
	
	private void setRefDoc(FieldVO field) {
		if (field.getEnumSource() == EnumSource.RefDoc ) {
			BaseDocVO baseDocVO = baseDocBizServiceImpl.getbaseDocById(field.getRefDocId());
			field.setOriginalDoc(baseDocVO);
			Map<String, Object> docMap = new HashMap<String, Object>();
			docMap.put("id", baseDocVO.getId());
			docMap.put("name", baseDocVO.getName());
			List<Map<String, Object>> items = new ArrayList<Map<String,Object>>();
			for (BaseDocDetailVO baseDocDetailVO:baseDocVO.getBaseDocDetailList()) {
				Map<String,Object> itemMap = new HashMap<String, Object>();
				itemMap.put("key",baseDocDetailVO.getId().toString());
				itemMap.put("title", baseDocDetailVO.getName());
				items.add(itemMap);		
			}
			docMap.put("items", items);
			field.setRefDoc(docMap);
		}	
	}
	
	private void setApi(FieldVO field) {
		if (field.getType() == FieldType.Lookup || field.getType()==FieldType.MasterDetail) {
			if (field.getMobileApiId() !=null && field.getMobileApiId()>0) {
				ApiVO mobileApiVO =  apiBizServiceImpl.getApi(field.getMobileApiId());
				field.setMobileApi(mobileApiVO);
			}
			
			if (field.getPcApiId() !=null && field.getPcApiId()>0) {
				ApiVO pcApiVO =  apiBizServiceImpl.getApi(field.getPcApiId());
				field.setPcApi(pcApiVO);
			}
		}	
	}
	
	private void setControlledBy(FieldVO field) {
		String controlledByStr = field.getControlledByStr();
		if ( !StringUtils.isEmpty(controlledByStr)) {
			String[] controlledBy = StringUtils.commaDelimitedListToStringArray(controlledByStr);
			field.setControlledBy(controlledBy);
		}	
	}
	
	private void copyFromOriginal(FieldVO fieldVO,FieldVO originalField) {
		fieldVO.setType(originalField.getType());
		fieldVO.setIsCustom(originalField.getIsCustom());
		fieldVO.setFullname(originalField.getFullname());	
		fieldVO.setObjId(originalField.getObjId());
		fieldVO.setIsRequired(originalField.getIsRequired());
		fieldVO.setIsDisplayable(originalField.getIsDisplayable());
		fieldVO.setIsFilterable(originalField.getIsFilterable());
		fieldVO.setIsReadonly(originalField.getIsReadonly());
		fieldVO.setExpression(originalField.getExpression());
		fieldVO.setExpressionType(originalField.getExpressionType());
		fieldVO.setSlot(originalField.getSlot());		
		fieldVO.setMobileApiId(originalField.getMobileApiId());
		fieldVO.setPcApiId(originalField.getPcApiId());
		fieldVO.setControlledByStr(originalField.getControlledByStr());
		fieldVO.setMobileUiType(originalField.getMobileUiType());
		fieldVO.setPcUiType(originalField.getPcUiType());
		fieldVO.setSortOrder(originalField.getSorOrder());
	}
	
	public List<Object> getCustomFieldTypes(Long objId) {
		List<Object> rs  = new ArrayList<Object>();
		Map<String, Integer> dataTypeMap = moduleServiceImpl.getTotalNumForMysqlDataTypes(objId);
		List<FieldVO> customFieldList = getCustomFieldList(objId);
		
		for(FieldVO fieldVO:customFieldList) {
			String mysqlDataType = getMysqlDataTypeFromSlot(fieldVO.getSlot());
			dataTypeMap.put(mysqlDataType, dataTypeMap.get(mysqlDataType) -1);
		}
		
		List<FieldTypeVO> fieldTypeList =  fieldHandler.getFieldTypeList();	
		for (FieldTypeVO fieldTypeVO:fieldTypeList) {
			if (fieldTypeVO.getOnlyPresetAvailable() == 1) {
				continue;
			} else {
				Map<String, Object> fieldTypeMap = new HashMap<String, Object>();
				fieldTypeMap.put("num", dataTypeMap.get(fieldTypeVO.getMysqlDatatype()));
				fieldTypeMap.put("type",fieldTypeVO.getType());
				fieldTypeMap.put("name",fieldTypeVO.getName());
				fieldTypeMap.put("length", fieldTypeVO.getLength());
				fieldTypeMap.put("precision", fieldTypeVO.getPrecision());
				fieldTypeMap.put("maxValue", fieldTypeVO.getMaxValue());
				fieldTypeMap.put("minValue", fieldTypeVO.getMinValue());
				rs.add(fieldTypeMap);
			}
		}
		return rs;
	}
	
	private String getMysqlDataTypeFromSlot(String slot) {
		return StringUtils.deleteAny(slot, "0123456789");
	}
	
}



